package top.chenyaohua.asm;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.*;

public class CustomMethodVisit extends MethodVisitor {

    private MethodMetadata methodMetadata;

    private CustomClassVisit customClassVisit;


    public CustomMethodVisit (MethodVisitor mv,CustomClassVisit customClassVisit) {
        super(Opcodes.ASM5, mv);
        this.customClassVisit = customClassVisit;
        List<MethodMetadata> methods = Optional.ofNullable(customClassVisit.getBeanMetadata().getMethodMetadata()).orElseGet(ArrayList::new);
        this.methodMetadata = methods.get(methods.size() - 1);
    }

    /**
     * 用于获取Annotation的默认值
     * @return
     */
    @Override
    public AnnotationVisitor visitAnnotationDefault () {

        AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();

        return new CustomAnnotationVisitor(annotationVisitor,this.customClassVisit,null,this);
    }


    /**
     * 在静态方法中局部变量表第一位变量就是方法参数   而在非静态方法中第一位变量是this对象本身  下面的方法写得有缺陷只考虑了静态方法
     * @param name
     * @param desc
     * @param signature
     * @param start
     * @param end
     * @param index
     */
    @Override
    public void visitLocalVariable (String name, String desc, String signature, Label start, Label end, int index) {

        Map<Integer, FieldMetadata> params = Optional.ofNullable(this.methodMetadata.getParams()).orElseGet(HashMap::new);

        if( "this".equals(name) || index > this.methodMetadata.getCount() ){
            super.visitLocalVariable(name, desc, signature, start, end, index);
            return;
        }

        FieldMetadata fieldMetadata = new FieldMetadata(name,desc);
        if( this.methodMetadata.isAccStatic() ){
            params.put(index,fieldMetadata);
        }else{
            params.put(index-1,fieldMetadata);
        }
        this.methodMetadata.setParams(params);
        super.visitLocalVariable(name, desc, signature, start, end, index);
    }


    @Override
    public AnnotationVisitor visitAnnotation (String desc, boolean visible) {

        AnnotationMetadata annotationMetadata = new AnnotationMetadata(desc);
        List<AnnotationMetadata> annos = Optional.ofNullable(methodMetadata.getAnnotations()).orElseGet(ArrayList::new);
        annos.add(annotationMetadata);
        this.methodMetadata.setAnnotations(annos);

        return new CustomAnnotationVisitor( super.visitAnnotation(desc, visible) ,this.customClassVisit,null,this);
    }

    @Override
    public AnnotationVisitor visitParameterAnnotation (int parameter, String desc, boolean visible) {

        FieldMetadata fieldMetadata = new FieldMetadata(null, null);
        AnnotationMetadata annotationMetadata = new AnnotationMetadata(desc);
        fieldMetadata.setAnnotations(Arrays.asList(annotationMetadata));

        Map<Integer, FieldMetadata> params =  Optional.ofNullable(methodMetadata.getParams()).orElseGet(() -> new HashMap<>());
        params.put(parameter, fieldMetadata);
        methodMetadata.setParams(params);

        return new CustomAnnotationVisitor( super.visitParameterAnnotation(parameter, desc, visible) ,this.customClassVisit, null ,this);
    }



    public MethodMetadata getMethodMetadata () {
        return methodMetadata;
    }

    public CustomClassVisit getCustomClassVisit () {
        return customClassVisit;
    }
}
